javascript clean-code-javascript(日本語訳)を読む
英語全くだめな子な私にとって、日本語訳があることほどありがたいことはないです。いつも皆さんお世話になっております。ありがとうございます。
コードは最初から完璧に書けるものではない。徐々に綺麗にしていくもんなんだよ。
ポイント
抽象的ポイント
コードを常に検索しやすく、解読しやすくしなさい
部品化を積極的に行い、「影響を小さく」を徹底する
1つの関数は1つの処理だけ行う
インターフェースに依存させる
変数
変数名には意味のある発音可能な名前をつけなさい
同じような種類のコードには同じ名前をつけなさい
マジックナンバーには名前をつけなさい
code: example.js
const MILLISECONDS_IN_A_DAY = 86400000;
setTimeout(blastOff, MILLISECONDS_IN_A_DAY);
解読しに悔いなら、中間変数を利用しなさい
仮名ではなく、ちゃんとした名前をつけなさい
code: exapmle.js
//NG
locations.forEach(l => {...})
//OK
locations.forEach(location => {...})
親の名前空間を無闇にプロパティ名にも利用する必要はない
code: example.js
// NG
class Car = {
carMake: 'Honda', carModel: 'Accord', carColor: 'Blue'
}
// OK
class Car = {
make: 'Honda', model: 'Accord', color: 'blue'
}
ブロック内で短絡・条件式を利用するくらいなら、デフォルト引数を使いなさい
関数
関数の引数は2つ以下に収めなさい
役割を小さくすることで、「影響を小さくする」を大事に。
2つより多くなるようなら、オブジェクトにまとめるなどの工夫をしなさい。
引数が多すぎてだるいなら、オブジェクトを引数にしなさい
関数は一つの処理だけ行うようにしなさい
関数名はちゃんと処理内容を表すようにしなさい
関数内で色々やりすぎてるなら分割しなさい。1関数-1処理!
引数にフラグ値を利用してはいけません
副作用(値を受け取り加工して返す以外の処理)はできるだけ避ける
DB書き込み、ファイル書き込み、APIを叩いて書き込み、とあるオブジェクトへの変更処理など
副作用を使う必要がある場合、その処理だけのサービスを作る
不用意にあちらこちらに副作用処理を含めるのはダメ
受け取ったオブジェクトを直接変更するのではなく、コピーしてから返す関数にしなさい。
code: sample.js
//NG
const addItemToCart = (cart, item) => {
cart.push({ item, date: Date.now() });
};
//OK
const addItemToCart = (cart, item) => {
};
グローバルオブジェクトの利用は禁止。絶対に他と衝突が起きてバグの原因になる。
今起きてなくても将来起きる可能性がある。
関数型言語っぽい書き方が使えるなら使うことを推奨します
code: sample.js
const totalOutput = programmerOutput
.map(output => output.linesOfCode)
.reduce((totalLines, lines) => totalLines + lines);
条件分岐はカプセル化して1つの関数として定義しなさい
できるだけ人間が読みやすくするために名付けを行う。
否定条件は避けなさい。直感的にわかりにくい。
条件分岐を避けなさい。ポリモーフィズムで対応できるならそうしなさい。
javascriptで型チェックを行いたいなら、素直にTypeScriptを利用しなさい
最適化に気を取られすぎない。本当にボトルネックになってるとこだけ見つけて最適化する
デッドコードを残さない
構造化
プロパティの直接利用を禁じて、getter/setterなどを利用してカプセル化を表現しなさい
DDDだとsetterすら許されない...
クラス
メソッドチェーンを使って、インスタンスの利用をよりクリーンにしなさい
code: sample.js
const car = new Car('Ford','F-150','red')
.setColor('pink')
.save();
継承よりもなるべくコンポジションを利用しなさい
SOLID
省略。別枠で再度勉強する
テスト
最終的にはTDDまで辿り着けるように鍛錬する
かばれっじツールを導入してテストカバー率を参考にする
1つのユニットで1つのテスト
並行処理
コールバックではなくPromiseを利用しなさい
更に言うとPromiseではなく、async/awaitを利用しなさい
エラー処理
エラーコードを返すのではなく、ちゃんとthrowしなさい
エラーを無視することはいけません
書き方
関数は上から下に使う順に書くと綺麗になる
コメント
コメントは意図を残すためにあり、補足のためにあるのではない
良いコードはそれだけで何をしてる自体の説明がつく。コメントの補足が必要ということは、名付けが下手くそだったり関数の分け方が甘い。
以下のような位置マーカーは避ける
code:sample.js
///////////////////////////////
// Scope aaa //////////////////
///////////////////////////////
理解・納得できるポイント
コードを常に検索しやすく読みやすくしろ
インターフェースに依存させる
変数名には意味のある発音可能な名前をつけなさい
同じような種類のコードには同じような名前をつけなさい
マジックナンバーには名前をつけなさい
解読しに悔いなら、中間変数を利用しなさい
仮名ではなく、ちゃんとした名前をつけなさい
親の名前空間を無闇にプロパティ名にも利用する必要はない
memo.icon冗長になっちゃうもんな。名前空間にいるうちは、グローバル変数でない限り、シンプルな名前にしとこう。DDDのドメイン領域と関係ない場合などもonigiri.w2.icon
ブロック内で短絡・条件式を利用するくらいなら、デフォルト引数を使いなさい
関数名はちゃんと処理内容を表すようにしなさい
副作用(値を受け取り加工して返す以外の処理)はできるだけ避ける
memo.icon
これはわかる気がする。副作用があると処理を追いづらくなるonigiri.w2.icon
人間が後から読むときに、影響範囲を読めるようにしなさい!!
あと、オブジェクトを受け取って、そのオブジェクトに直接変更を加えるのも無し。
変更を加えるなら、そのオブジェクトをコピーして返すっていう処理をした方がいい。
そうすることで、この関数が何をしたのか?をちゃんと追える。
副作用を使う必要がある場合、その処理だけのサービスを作る
memo.icon副作用は副作用だけを行うサービスに集めろ!!!onigiri.w2.icon
受け取ったオブジェクトを直接変更するのではなく、コピーしてから返す関数にしなさい
グローバルオブジェクトの利用は禁止。絶対に他と衝突が起きてバグの原因になる
関数型言語っぽい書き方が使えるなら使うことを推奨します
メソッドチェーンを使って、インスタンスの利用をよりクリーンにしなさい
否定条件は避けなさい。直感的にわかりにくい。
javascriptで型チェックを行いたいなら、素直にTypeScriptを利用しなさい
最適化に気を取られすぎない。本当にボトルネックになってるとこだけ見つけて最適化する
デッドコードを残さない
プロパティの直接利用を禁じて、getter/setterなどを利用してカプセル化を表現しなさい
エラーコードを返すのではなく、ちゃんとthrowしなさい
関数は上から下に使う順に書くと綺麗になる
コメントは意図を残すためにあり、補足のためにあるのではない
良いコードはそれだけで何をしてる自体の説明がつく
位置マーカーの利用は避ける
理解不能・調べる必要あるポイント
部品化を積極的に行い、影響を小さくする
関数は一つの処理だけ行うようにしなさい
関数内で色々やりすぎてるなら分割しなさい。1関数-1処理!
1つの関数は1つの処理だけ行う
q.icon部品化しすぎてうまくいかなくなることもあるのでは?onigiri.w2.icon
a.icon部品化するとその部品を細かく見る必要がなくなる。綺麗に名付けして単一責任の原則守って、副作用なく作ってればね。
引数にフラグ値を利用してはいけません
q.iconポリモーフィズムを使えって言ってたけど、どういうことだろう?どういう効能がある?onigiri.w2.icon
条件分岐はカプセル化して1つの関数として定義しなさい
条件分岐を避けなさい。ポリモーフィズムで対応できるならそうしなさい
memo.iconわかるようなわからんようなonigiri.w2.icon
関数の引数は2つ以下に収めなさい
memo.iconちょっと実感が湧かない。なんで引数が多すぎるとダメなの?の実感がonigiri.w2.icon
継承よりもなるべくコンポジションを利用しなさい
memo.iconしっかり言語化できるわけではないonigiri.w2.icon
所感.icon
仮名ではなく、ちゃんとした名前をつけなさい
仮名の方がいい時もあると思うonigiri.w2.icon
例えば、仮名に使ってる変数がすぐに消える時。足が長くない時は、短命の方がコードが冗長にならずに逆に読みやすくなるはず。
ブロックが長くなって、仮名変数を長々と使うことになるなら、ちゃんとした名前をつけたほうがいいが。
ただ、コードの改修によって、最初は短命だったものが長命になる可能性もあることを考えると、ちゃんとした名前をつけておいた方がいいのかもなぁ...
それなら、長くなった時にちゃんとした名前をつければいいわけやから、やっぱり仮名を使った方がいい場面では積極的に使っていこう。
関数は一つの処理だけ行うようにしなさい
重要.iconなんかモヤモヤするのよなぁ。ここ。なんかちゃう気がする。
code: example.js
function emailActiveClients(clients) {
clients
.filter(isActiveClient)
.forEach(email);
}
function isActiveClient(client) {
const clientRecord = database.lookup(client);
return clientRecord.isActive();
}
例えば上記のコード
確かにisActiveClientに出してるけど、結局はemailActiveClientsの中でそのisActiveClientsの操作が行われてるわけやん?
つまり、emailActiveClientsでは、2つの処理が結局行われてることにならん?
関数は1つの処理だけを行うようにしなさいという説明は間違ってるんじゃない?
「関数は1つの処理だけを実装し、できる限り他の役割の実装を別に移譲しなさい」とかの方がいい?
なんか難しいな。言いたいことをうまく言えない。
参考:
コツ ・考え方
関数の目的(やりたいこと)を定義する
関数の目的を達成するまでに必要な手段を別関数化する
「あれしてこれして」ってのが1つの関数内で言えてしまうなら、ガッツリ分けたほうがいい
関数を分けて、親関数(Facade)から利用するイメージ
何でもかんでも分ければいいってものでもないと思うonigiri.w2.icon
確かに「あれしてこれして」ってあったとしても、そもそもそれらの処理が分かれることがない。
絶対に一緒に使われるもの。どれか1つだけ使われるとかではなく、一緒に使われるとかなら、分ける必要がない。逆に冗長になっちゃう。
引数にフラグ値を利用してはいけません
これもなぁ、結局クライアント側で条件分岐するくないか?onigiri.w2.icon
なぜ、親に問題を移しただけですやん?違う?
code: good.js
function createFile(name) {
fs.create(name);
}
function createTempFile(name) {
createFile(./temp/${name});
}